#pragma once

// -----------------------------------------------------------------------------
#include "Win32.Diagnostics.Result.h"
#include "Win32.Memory.h"

namespace Kif
{
namespace Win32
{

/// <summary>Provide a memory buffer management</summary>
template <typename T>
class MemoryBuffer
{
private:
   Diagnostics::Result lastResult;
   Memory memory;
   size_t sizeInBytes;
   size_t size;
   bool disposable;

public:

   T *Buffer;

   MemoryBuffer()
   {
      Buffer = NULL;
      sizeInBytes = 0;
      size = 0;
      disposable = false;
   }  // end of MemoryBuffer (ctor)

   inline bool IsNull()
   {
      return(Buffer == NULL);
   }  // end of IsNull

   inline Diagnostics::Result *GetLastResult()
   {
      return(&lastResult);
   }  // end of GetLastResult

   inline size_t GetSize()
   {
      return(size);
   }  // end of GetSize

   inline size_t GetSizeInBytes()
   {
      return(sizeInBytes);
   }  // end of GetSizeInBytes

   inline DWORD GetSizeOfType()
   {
      return(sizeof(T));
   }  // end of GetSizeOfType

   /// <summary>free allocated memory if disposable</summary>
   inline void Dispose()
   {
      if (disposable && (Buffer != NULL))
         memory.free(Buffer);
      Buffer = NULL;
      sizeInBytes = 0;
      size = 0;
      disposable = false;
   }  // end of Free

   /// <summary>set the buffer with disposable memory</summary>
   /// <param name="buffer">buffer to set</param>
   /// <param name="sizeInBytes">buffer size in bytes</param>
   /// <param name="disposable">true if the given buffer memory can be
   /// disposed here</param>
   inline void SetBuffer(T *buffer, size_t sizeInBytes, bool disposable)
   {
      Dispose();
      Buffer = buffer;
      if (Buffer == NULL)
         sizeInBytes = 0;
      this->sizeInBytes = sizeInBytes;
      if (sizeInBytes > 0)
         this->size = sizeInBytes / sizeof(T);
      this->disposable = disposable;
   }  // end of SetBuffer

   /// <summary>set the buffer with non-disposable memory</summary>
   /// <param name="buffer">buffer to set</param>
   /// <param name="buffer">buffer size in bytes</param>
   inline void SetNonDiposableBuffer(T *buffer, size_t sizeInBytes)
   {
      SetDiposableBuffer(buffer,sizeInBytes,false);
   }  // end of SetNonDiposableBuffer

   /// <summary>set the buffer with non-disposable memory</summary>
   /// <param name="buffer">buffer to set</param>
   /// <param name="buffer">buffer size in bytes</param>
   inline void SetBuffer(T *buffer, size_t sizeInBytes)
   {
      SetBuffer(buffer,sizeInBytes,false);
   }  // end of SetBuffer

   /// <summary>set the buffer with disposable memory</summary>
   /// <param name="buffer">buffer to set</param>
   /// <param name="buffer">buffer size in bytes</param>
   inline void SetDiposableBuffer(T *buffer, size_t sizeInBytes)
   {
      SetBuffer(buffer,sizeInBytes,true);
   }  // end of SetDiposableBuffer

   /// <summary>allocate a buffer of the given size in bytes</summary>
   /// <param name="buffer">buffer size in bytes</param>
   inline T *Alloc(size_t size)
   {
      size_t sizeInBytes = size*sizeof(T);
      T *buffer = (T*)memory.alloc(sizeInBytes);
      SetBuffer(buffer,sizeInBytes,true);
      return(Buffer);
   }  // end of Alloc

   /// <summary>Copy the buffer with disposable memory</summary>
   /// <param name="buffer">buffer to set</param>
   /// <param name="sizeInBytes">buffer size in bytes</param>
   /// <returns>a pointer to the allocated buffer is returned</returns>
   inline T *Copy(T *buffer, size_t sizeInBytes)
   {
      Dispose();
      Alloc(sizeInBytes);
      if (!Buffer)
         return(NULL);
      BYTE *d = (BYTE*)Buffer;
      BYTE *s = (BYTE*)buffer;
      size_t i;
      for(i=0; i < sizeInBytes; i++)
         d[i] = s[i];
      return Buffer;
   }  // end of Copy

   /// <summary>Clear the allocated memory buffer</summary>
   inline void ClearBuffer()
   {
      size_t i;
      for(i=0; i < sizeInBytes; i++)
         *(Buffer+i) = NULL;
   }  // end of ClearBuffer

}  ;  // end of MemoryBuffer

}  // end of Kif::Win32
}  // end of Kif

